optionalWith: A generalized optional modifier.#78
optionalWith: A generalized optional modifier.#78m-bock wants to merge 3 commits intogaryb:masterfrom
optionalWith: A generalized optional modifier.#78Conversation
|
I'm not necessarily saying no to this contribution since the ergonomics of this are probably better for simple cases, but are you aware of the use of |
|
Got it, I guess you mean something like this: import Prelude
import Data.Codec.Argonaut (JsonCodec)
import Data.Codec.Argonaut as CA
import Data.Codec.Argonaut.Record as CR
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Profunctor (dimap)
type User =
{ name ∷ String
, age ∷ Int
, hobbies ∷ Array String
}
codecUser ∷ JsonCodec User
codecUser =
dimap
( \r → r
{ name = Just r.name
, age = Just r.age
, hobbies = if r.hobbies == [] then Nothing else Just r.hobbies
}
)
( \r → r
{ name = fromMaybe "Max" r.name
, age = fromMaybe 0 r.age
, hobbies = fromMaybe [] r.hobbies
}
)
$ CA.object "User"
$ CR.record
{ name: CR.optional CA.string
, age: CR.optional CA.int
, hobbies: CR.optional (CA.array CA.string)
}I will close this PR because in the meanwhile I worked on an alternative approach. |
|
Yeah, exactly, although I've only generally had one field that needed that kind of treatment at a time, so it's a little less boilerplatey - but still not as ergonomic as the field level combinator you're proposing. Just thought I'd mention |
Current state of optional field parsing with
optionalLet’s say we have a record with an optional
flagfield:The appropiate codec for this would look like:
This setup is convenient, as it supports multiple JSON inputs:
{}is parsed as{ flag: Nothing }{ "flag": true }is parsed as{ flag: Just true }{ "flag": false }is parsed as{ flag: Just false }Introducing
optionalWithHowever, in many use cases, working with a
Maybe Booleanisn’t ideal. Often, we’d prefer to use a plainBoolean, treating bothNothingandJust falseas false:With the current version of
codec-argonaut, we’d need to define bothSampleandSample2, along with conversion functions between them.To avoid this, the PR introduces a new modifier:
optionalWith, a more flexible version ofoptional.Here’s how it can be used:
This codec handles the following cases directly:
{}is decoded as{ flag: false }{ "flag": true }is decoded as{ flag: true }{ "flag": false }is decoded as{ flag: false }Other Usecases
This pattern is especially useful when working with JavaScript APIs, where fields are often omitted instead of explicitly set to a default or “empty” value.
Other examples where
optionalWithis useful include:Maybe (Maybe a)to justMaybe a, useful for fields that can be either null or missingBonus:
optionalWithis a generalization ofoptional, which can now internally be redefined as:As a result, this MR introduces no code duplication. Tests are added that verify the behavior.